package net.sf.rose.web.util;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Logger;
import org.simpleframework.xml.Attribute;
import org.simpleframework.xml.Element;
import org.simpleframework.xml.Root;

import net.sf.rose.boot.BootStart;
import net.sf.rose.jdbc.KeyGenerator;

/**
 * @author fengjian E-mail: 9110530@qq.com
 * @version 创建时间：2019年05月17日 
 * 类说明：自定义的用户会话管理器
 * 二个参数：时间和空间。时间是Session保留的时间，空间是Session存储的空间大小。
 * 启动时系统预设置二个参数，当空间满了或回收周期到了就执行回收算法。 当回收算法执行过频时，系统会增大空间或减少Session保留时间。
 * 初始空间是100个名额，时间是60分钟，算法执行周期与保留时间一致。
 * 如果在周期一半的时间就需要执行回收算法，则空间放大一倍和时间减少10分钟，时间最小值为10分钟。
 */
@Root
public class SessionUtils implements BootStart, Runnable {

	private static Logger LOG = Logger.getLogger(SessionUtils.class);

	/** 缓存数据存储空间 */
	private static Map<String, SessionUtils> sessionCache = new HashMap<>();

	public static Map<String, SessionUtils> getSessionCache() {
		return sessionCache;
	}

	/**
	 * 设置用户对象缓存
	 * 
	 * @param user - 用户对象实例
	 * @return 缓存数据的token值
	 */
	public static String addUserBeanCache(Object user) {
		String token = KeyGenerator.getSystemUUID();
		SessionUtils bean = new SessionUtils();
		bean.data = user;
		bean.today = new Date();
		sessionCache.put(token, bean);
		return token;
	}

	/**
	 * 获取用户对象缓存
	 * 
	 * @param token - token值
	 * @return 用户对象实例
	 */
	@SuppressWarnings("unchecked")
	public static <T> T getUserBeanCache(String token) {
		if (token == null) {
			return null;
		}
		Object obj = sessionCache.get(token);
		if (obj != null) {
			SessionUtils bean = (SessionUtils) obj;
			bean.today = new Date();
			sessionCache.put(token, bean);
			return (T) bean.data;
		}
		return null;
	}

	/**
	 * 设置用户对象缓存
	 * 
	 * @param user - 用户对象实例
	 * @return 缓存数据的token值
	 */
	public static void removeUserBeanCache(String token) {
		sessionCache.remove(token);
	}

	@Override
	public void run() {
		while (true) {
			long time = (new Date()).getTime();
			Map<String, SessionUtils> map = new HashMap<>();
			for (String key : sessionCache.keySet()) {
				SessionUtils bean = sessionCache.get(key);
				if ((time - bean.today.getTime()) < cacheKeepTime) {
					map.put(key, bean);
				}
			}
			if (sessionCache.size() > cacheSize) {
				cacheSize = cacheSize * 2;
				cacheKeepTime = (int) (cacheKeepTime * 0.9);
			}
			sessionCache = map;
			try {
				StringBuilder sb = new StringBuilder();
				sb.append("\n********************************************\n");
				sb.append(description + "缓存管理器大小为：" + cacheSize + '\n');
				sb.append("目前共有：" + sessionCache.size() + "个在线用户\n");
				sb.append("缓存时间为：" + cacheKeepTime + "\n");
				sb.append("********************************************\n");
				LOG.error(sb.toString());
				Thread.sleep(cacheKeepTime);
			} catch (InterruptedException e) {
				LOG.error(e.getMessage(), e);
			}
		}
	}

	/** 是否需要启动 */
	@Attribute
	private boolean needStart = false;

	/** 用户信息在缓存中的保留时长(秒) */
	@Element
	private String description = null;

	/** 缓存初始大小 */
	@Element
	private int cacheSize = 200;

	/** 缓存数据初始保留时间 */
	@Element
	private int cacheKeepTime = 60 * 60 * 1000;

	/**
	 * 需要启动
	 */
	@Override
	public boolean needStart() {
		return needStart;
	}

	/**
	 * 启动执行的方法
	 */
	@Override
	public void start() {
		if (description == null) {
			description = this.getClass().getName();
		}
		// 如果没有开启Redis缓存，则开启此缓存服务线程
		Thread t = new Thread(this);
		t.start();
	}

	/** 缓存数据 */
	private Object data = null;

	/** 缓存时间 */
	private Date today = null;

	@SuppressWarnings("unchecked")
	public <T> T getData() {
		return (T) this.data;
	}

	public Date getToday() {
		return this.today;
	}

}
